
#include "RealTimeDealModel.h"

#include <bondlib/RealTimeDeal/BondMarketStreamV2.h>
#include <qglobal.h>

#include "MultiBrokerStat.h"
#include "RealTimeDealFilter.h"
#include "RealTimeDealIndexList.h"
#include "RealTimeDealSorter.h"
#include "ScreenRecordCache.h"
typedef MarketStreamInfo Record;

namespace detail {
void GetColumnOrders(const CSortInfoManager& sortinfo,
                     std::vector<ColumnOrder>& orders) {
  orders.clear();
  bool code_found = true;
  for (int i = 0; i < (int)sortinfo.m_vecSortInfo.size(); i++) {
    ColumnOrder co;
    co.comlumn = sortinfo.m_vecSortInfo.at(i).m_nSortKey;
    co.ascend = !sortinfo.m_vecSortInfo.at(i).m_bDesc;
    code_found = code_found ? true : (co.comlumn == VBOND_CODE);
    orders.push_back(co);
  }

  // 当VBOND_CODE不存在的时候,自动按照VBOND_CODE排序
  if (!code_found) {
    // VBOND_CODE
    ColumnOrder co;
    co.comlumn = VBOND_CODE;
    co.ascend = true;
    orders.push_back(co);
  }
}
}  // namespace detail
RealTimeDealModel::RealTimeDealModel()
    : m_batchid(-1),
      m_stateid(0),
      m_need_update(true),
      m_sortinfo_set(false),
      m_bCFETS(false) {
  m_multi = new MultiChecker();
  m_keys = new DealIndexList();
  m_screen_cache = new ScreenCache();
  m_sorter = new Sorter();
  m_filter = new Filter();

  // m_keys的每个更新,都会让m_sorter来对记录进行比较
  // m_sorter->SetSortInfo();
  m_keys->SetComparator(new detail::DealIndexComparator(m_sorter));
}

#define MEMCATCH(BLOCK)                                             \
  try {                                                             \
    BLOCK;                                                          \
  } catch (...) {                                                   \
    DVIEW("BLOCK:%s triggered a CMemoryException,NAME=%s", #BLOCK); \
  }
#define SAFE_DELETE_PTR(ptr) \
  if (ptr) {                 \
    delete ptr;              \
    ptr = nullptr;           \
  }
#define SAFE_DELETE_PTR_ARR(ptr) \
  if (ptr) {                     \
    MEMCATCH(delete[] ptr);      \
    ptr = nullptr;               \
  }

RealTimeDealModel::~RealTimeDealModel() {
  SAFE_DELETE_PTR(m_multi);
  SAFE_DELETE_PTR(m_keys);
  SAFE_DELETE_PTR(m_screen_cache);
  SAFE_DELETE_PTR(m_sorter);
  SAFE_DELETE_PTR(m_filter);
}

int RealTimeDealModel::GetMultiCount() const {
  if (m_multi && m_multi->IsEnable()) return m_multi->GetCount();
  return 0;
}
bool RealTimeDealModel::GetCacheId(int row, DealIndex& id) {
  return m_screen_cache->GetIdByRow(row, id);
}
bool RealTimeDealModel::GetCacheRow(const DealIndex& id, int& row) {
  return m_screen_cache->GetRowById(id, row);
}
bool RealTimeDealModel::GetCacheRecord(const DealIndex& id,
                                       MarketStreamInfo& record) const {
  return m_screen_cache->GetRecord(id, record);
}

int RealTimeDealModel::GetCFETSAllRecords(MarketStreamInfo* records) {
  int ncount = 0, pos = 0, rowCount = qMin(500, GetCount());
  CMarketStream::cfectsStream().GetRecords(this, pos, rowCount, records);
  return ncount;
}

int RealTimeDealModel::GetRecords(int& pos, int rowCount,
                                  MarketStreamInfo* records) {
  int old_batch = this->GetBatchId();
  int ncount = 0;

  if (m_bCFETS)
    ncount =
        CMarketStream::cfectsStream().GetRecords(this, pos, rowCount, records);
  else
    ncount =
        CMarketStream::bondStream().GetRecords(this, pos, rowCount, records);

  m_screen_cache->Clear();
  for (int i = 0; i < ncount; i++) {
    m_screen_cache->AddRecord(records[i].m_body.m_id, pos + i, i + 1,
                              records[i]);
  }
  int new_batch = this->GetBatchId();
  m_need_update = false;
  return ncount;
}

bool RealTimeDealModel::IsMultiEnable() const { return m_multi->IsEnable(); }

void RealTimeDealModel::CheckMulti(const IRecordMap* values) {
  // UI线程,外部加锁,只能由CBondDealList.GetRecords来调用;
  Q_ASSERT(m_multi->IsEnable());
  std::vector<DealIndex> allkeys;
  m_keys->GetAllKeys(allkeys);
  m_multi->Clear(m_multi->IsEnable());

  if (values) {
    for (int i = 0; i < (int)allkeys.size(); i++) {
      const Record* record = (const Record*)values->FindRecord(allkeys[i]);
      if (record) {
        m_multi->AddBroker(record->m_body.m_bondkey,
                           record->m_body.m_listedmarket);
      }
    }
  }
}

void RealTimeDealModel::ClearFlash() {}
int RealTimeDealModel::GetKeys(int pos, int count, void* keys) {
  return m_keys->GetKeys(pos, count, (DealIndex*)keys);
}
void RealTimeDealModel::ResetKeys() {
  if (m_keys) m_keys->Clear();
}
int RealTimeDealModel::GetCount() const { return m_keys->GetCount(); }
int64 RealTimeDealModel::GetState() const { return m_stateid; }
void RealTimeDealModel::SetState(int64 state) { m_stateid = state; }
void RealTimeDealModel::AddFlash(int batchid, const void* pinfo) {
  const MarketStreamInfo& info = *(const MarketStreamInfo*)pinfo;
  DealIndex id = info.m_body.m_id;
  int nDealStatus = atoi(info.m_body.m_dealStatus);

  if (!m_flasher) return;

  if (nDealStatus < 4)
    m_flasher->addFlash(id.id);
  else
    m_flasher->removeFlash(id.id);
}
void RealTimeDealModel::AddRecord(int batchid, const void* pinfo) {
  // 逐个收取记录,要进行过滤,过滤之后才能决定要不要
  // record是已经通过了底层的检测
  if (batchid > m_batchid && batchid >= 0) SetBatchId(batchid);
  if (!m_sortinfo_set) {
    // m_keys的Insert会调用m_sorter的
    // RealTimeDealSorter::CompareIndex函数来对两条记录进行排序
    // 首次加入一条记录的时候,即设置排序,且必须设置排序
    // 用户点击了排序后,会将m_batchid设为-1,触发SyncKeys,进而调用SortImpl来设置排序信息
    m_sortinfo_set = true;
    std::vector<detail::ColumnOrder> orders;
    GetColumnOrders(m_sort_info, orders);
    int ncorpid = atoi(m_sort_info.GetSortCorp());
    m_sorter->SetSortInfo(orders);
  }
  const MarketStreamInfo& info = *(const MarketStreamInfo*)pinfo;
  bool filterPassed = m_filter->IsDealPassed(info.m_body.m_id, pinfo);
  DealIndex id = info.m_body.m_id;
  int nDealStatus = atoi(info.m_body.m_dealStatus);
  if (nDealStatus < 4 || nDealStatus == 8)  // 更新统计
  {
    if (!filterPassed) return;
    m_keys->Insert(id);
    if (m_flasher) m_flasher->addFlash(id.id);
    m_multi->AddBroker(info.m_body.m_bondkey, info.m_body.m_listedmarket);
  } else  // 删除,忽略过滤条件,底层要删除数据,UI中不管是否过滤,必定要删除,但是经纪商统计必须关注过滤
  {
    m_keys->Erase(id);
    if (m_flasher) m_flasher->removeFlash(id.id);
    if (filterPassed)
      m_multi->RemoveBroker(info.m_body.m_bondkey, info.m_body.m_listedmarket);
  }
}
void RealTimeDealModel::SyncKeys(const IBatchedKeys* keys,
                                 const IRecordMap* records) {
  /*
          keys	:	是底层的最新成交数据的索引,按照time递减排列
          records	:	是底层的所有成交数据的容器,map<索引,成交记录>
          调用线程:   UI线程,外部已经加锁,是底层容器的锁
          功能	:	用于重建自身的成交纪录的索引
  */
  // 内部对每个DealIndex进行过滤,创建自身的
  // 将keys的索引拷贝到自身,并对结果使用过滤器过滤

  /*
  1.设置过滤器:普通,常用操作有:左侧过滤器面板,顶部过滤器tab,顶部broker;
  CBondDealList::Reload
  2.设定排序:普通,SetSortInfo,重新排序
  锁定CBondDealList
  3.拖动滚动条:频繁,只是调用CBondDealList::GetRecords从底层拿数据
  4.msgpush:自身更新
  */

  // 1.对底层数据的索引进行过滤
  std::vector<DealIndex> allkeys, passed;
  keys->GetKeys(allkeys);
  m_multi->Clear(m_multi->IsEnable());
  for (int i = 0; i < (int)allkeys.size(); i++) {
    DealIndex id = allkeys[i];
    const Record* record = (const Record*)records->FindRecord(id);
    if (record) {
      if (m_filter->IsDealPassed(id, record)) {
        passed.push_back(id);
        m_multi->AddBroker(record->m_body.m_bondkey,
                           record->m_body.m_listedmarket);
      }
    }
  }

  SetBatchId(keys->GetBatchId());
  // 对passedpassed行排序
  SortImpl(passed, records, true);
}
void RealTimeDealModel::StartCompare(const IRecordMap* records) {
  Q_ASSERT(m_sorter);
  m_sorter->BindCompareMap(records, true);
}
void RealTimeDealModel::EndCompare(const IRecordMap* records) {
  Q_ASSERT(m_sorter);
  m_sorter->BindCompareMap(records, false);
}
void RealTimeDealModel::SortImpl(std::vector<DealIndex>& keys,
                                 const IRecordMap* records, bool force) {
  std::vector<detail::ColumnOrder> orders;
  GetColumnOrders(m_sort_info, orders);
  int ncorpid = atoi(m_sort_info.GetSortCorp());
  // 对passedpassed行排序
  m_sorter->Sort(orders, keys, records, true);

  // 增加到有序容器中
  m_keys->BeginPush(keys.size());
  for (int i = 0; i < (int)keys.size(); i++) {
    m_keys->Push(keys[i]);
  }
  m_keys->EndPush(false);
}
void RealTimeDealModel::OnSort()  // 1000
{
  // 界面设置好排序参数
  SetBatchId(-1);
  m_multi->Clear(m_multi->IsEnable());
  m_need_update = true;
}

void RealTimeDealModel::OnFilter(bool multiEnable)  // 1000
{
  // 界面设置好过滤参数
  // CBondDealList::Reload
  SetBatchId(-1);  // 后续GetRecords会同步重建所有的
  m_multi->Clear(multiEnable);
  m_need_update = true;
  m_sortinfo_set = false;
}

void RealTimeDealModel::OnScroll()  // 50
{
  m_need_update = true;
  /*


  */
}

void RealTimeDealModel::OnPush()  // 300
{
  // 只处理当前消息的DealIndex的增删
  // 如果恰好增的在CBondDealList中无效,那么同时也删除;
  // 重刷界面即可CBondDealList.GetRecords
  // GetRecords时,自动更新本身的m_batchid和m_multi 标志;
  // Record records[128] = { 0 };
  // CBondDealList::Get().GetRecords(this, 0, 0, records);
}
